//
//  MEDataStorage.m
//  MeeLive
//
//  Created by guangling.hou on 14/12/17.
//  Copyright (c) 2014年 Meelive. All rights reserved.
//

#import "IKSmallFileStorage.h"
#import "FCBasics.h"
#import "IKDownloader.h"
#import "IKDownloader.h"
#import <CommonCrypto/CommonDigest.h>
#import <IKCrypt/IKSecurityTool.h>
#import "CS_FileManager.h"

static NSString *const FileStorageDirectory = @"download";

typedef enum : NSUInteger {
    MEFILE_TO_DOWNLOAD,
    MEFILE_FINISH,
    MEFILE_TO_DELETE
} ME_DOWNLOAD_STAT;


@interface DownloadContextAtom : NSObject
//当前状态
@property(nonatomic, assign) ME_DOWNLOAD_STAT stat;
//本地的url
@property(nonatomic, copy) NSString *localUrl;
//下载进度
@property(nonatomic, assign) NSInteger progress;
//下载器 有可能用到
@property(nonatomic, strong) id downloader;

- (NSDictionary *)getDict;

+ (id)downloadContextAtomWithDic:(NSDictionary *)dict;

@end

@interface DownloadContext : NSObject

@property(nonatomic, copy, readonly) NSDictionary *urlToAtoms;

- (id)initWithFile:(NSString *)path;
- (void)syncDownloadContextAtomWithUrl:(NSString *)url stat:(ME_DOWNLOAD_STAT)stat;
- (void)syncWithUrls:(NSArray *)urlArray;
- (BOOL)isFinishedTaskCount;
- (NSInteger)progress;
- (void)delDownloadContextAtomWithUrl:(NSString *)url;
- (NSString *)localFileNameWithUrl:(NSString *)url;

@end


@implementation DownloadContextAtom

- (id)init {
    return [self initWithUrl:nil];
}

- (NSString *)md5Encrypt:(NSString *)p {
    return [IKSecurityTool md5Encrypt:p];
}

- (id)initWithUrl:(NSString *)url {
    if (self = [super init]) {
        self.stat = MEFILE_TO_DOWNLOAD;
        self.progress = 0;
        if (url) {
            self.localUrl = [NSString stringWithFormat:@"%@", [self md5Encrypt:url]];
        }
    }
    return self;
}

- (NSDictionary *)getDict {
    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
    [dict setObject:[NSNumber numberWithInteger:self.stat] forKey:@"stat"];
    [dict setObject:self.localUrl forKey:@"localUrl"];
    return dict;
}

+ (id)downloadContextAtomWithDic:(NSDictionary *)dict {
    if (!dict) {
        return nil;
    }
    
    DownloadContextAtom *atom = [[DownloadContextAtom alloc] init];
    atom.stat = [[dict objectForKey:@"stat"] integerValue];
    atom.localUrl = [dict objectForKey:@"localUrl"];
    
    return atom;
}

- (void)setStat:(ME_DOWNLOAD_STAT)stat {
    _stat = stat;
    
    switch (stat) {
        case MEFILE_TO_DOWNLOAD:
        case MEFILE_TO_DELETE:
            self.progress = 0;
            break;
            
        case MEFILE_FINISH:
            self.progress = 100;
            break;
            
        default:
            break;
    }
}

@end

@interface DownloadContext () {
    NSMutableDictionary<NSString *, DownloadContextAtom *> *_urlToAtoms;
    NSString *_path;
    NSMutableDictionary<NSString *, NSDictionary *> *_fileDict;
    NSInteger _all;
    NSInteger _finishedTaskCount;
}
@end

@implementation DownloadContext

- (NSDictionary *)urlToAtoms {
    return [_urlToAtoms copy];
}

- (id)init {
    NSAssert(FALSE, @"can't not call init");
    return self;
}

- (id)initWithFile:(NSString *)path {
    if (self = [super init]) {
        _urlToAtoms = [[NSMutableDictionary alloc] init];
        _all = 0;
        _finishedTaskCount = 0;
        _fileDict = [[NSMutableDictionary alloc] init];
        _path = path;
        NSDictionary *tmpDict = [[NSDictionary alloc] initWithContentsOfFile:path];
        
        if (tmpDict) {
            for (NSString *key in [tmpDict allKeys]) {
                NSDictionary *at = [tmpDict objectForKey:key];
                DownloadContextAtom *atom = [DownloadContextAtom downloadContextAtomWithDic:at];
                
                if (!atom) {
                    continue;
                }
                
                [_urlToAtoms setObject:atom forKey:key];
                [_fileDict setObject:at forKey:key];
                
                if (atom.stat != MEFILE_TO_DELETE) {
                    _all++;
                }
                
                if (atom.stat == MEFILE_FINISH) {
                    _finishedTaskCount++;
                }
            }
        }
    }
    return self;
}

- (void)_syncFile {
    if (_fileDict && _path) {
        [_fileDict writeToFile:_path atomically:YES];
    }
}

- (void)syncWithUrls:(NSArray *)urlArray {
    NSMutableSet *urlSet = [NSMutableSet setWithArray:urlArray];
    
    for (NSString *url in [_urlToAtoms allKeys]) {
        DownloadContextAtom *atom = [_urlToAtoms objectForKey:url];
        
        if ([urlSet containsObject:url]) {
            // add
            [urlSet removeObject:url];
            if (atom.stat != MEFILE_FINISH) {
                if (atom.stat == MEFILE_TO_DELETE) {
                    _all++;
                }
                atom.stat = MEFILE_TO_DOWNLOAD;
                NSDictionary *d = [atom getDict];
                [_fileDict setObject:d forKey:url];
            }
        } else {
            // del
            if (atom.stat != MEFILE_TO_DELETE) {
                _all--;
            }
            if (atom.stat == MEFILE_FINISH) {
                _finishedTaskCount--;
            }
            atom.stat = MEFILE_TO_DELETE;
            NSDictionary *d = [atom getDict];
            [_fileDict setObject:d forKey:url];
        }
    }
    
    for (NSString *url in urlSet) {
        DownloadContextAtom *atom = [[DownloadContextAtom alloc] initWithUrl:url];
        //        IKLog(@"U:%@ --- K:%@", url, atom.localUrl);
        [_urlToAtoms setObject:atom forKey:url];
        NSDictionary *d = [atom getDict];
        [_fileDict setObject:d forKey:url];
        _all++;
    }
}

- (BOOL)isFinishedTaskCount {
    return (_finishedTaskCount == _all);
}

- (NSInteger)progress {
    return ((double)_finishedTaskCount / (double)_all) * 100;
}

- (void)delDownloadContextAtomWithUrl:(NSString *)url {
    DownloadContextAtom *atom = [_urlToAtoms objectForKey:url];
    if (atom) {
        if (atom.stat != MEFILE_TO_DELETE) {
            _all--;
        }
        if (atom.stat == MEFILE_FINISH) {
            _finishedTaskCount--;
        }
        [_urlToAtoms removeObjectForKey:url];
        [_fileDict removeObjectForKey:url];
    }
}

- (NSString *)localFileNameWithUrl:(NSString *)url {
    if (!url) {
        return nil;
    }
    DownloadContextAtom *atom = [_urlToAtoms objectForKey:url];
    return atom.localUrl;
}

- (void)syncDownloadContextAtomWithUrl:(NSString *)url stat:(ME_DOWNLOAD_STAT)stat {
    
    DownloadContextAtom *atom = [_urlToAtoms objectForKey:url];
    
    if (!atom) {
        atom = [[DownloadContextAtom alloc] initWithUrl:url];
        [_fileDict setObject:[atom getDict] forKey:url];
        _all++;
    }
    if (stat == atom.stat) {
        return;
    }
    if (atom.stat == MEFILE_FINISH) {
        _finishedTaskCount--;
    }
    
    atom.stat = stat;
    if (atom.stat == MEFILE_FINISH) {
        _finishedTaskCount++;
    }
    if (atom.stat == MEFILE_TO_DELETE) {
        _all--;
    }
    
    [_fileDict setObject:[atom getDict] forKey:url];
    //  [self _syncFile];
}

@end

@interface IKSmallFileStorage () <IKDownloadDelegate> {
    NSString *_pathKey;
    NSString *_docPath;
    DownloadContext *_context;
    DownLoadFileType _fileType;
    NSMutableArray *_downloadArray;
    BOOL _isAsync;
    NSInteger _taskCount;  //批量下载任务数量
}
@end

@implementation IKSmallFileStorage

- (id)init {
    NSAssert(TRUE, @"init error!!!!");
    return [self initWithKey:@"" type:SMALL_TYPE];
}

- (id)initWithKey:(NSString *)key {
    return [self initWithKey:key type:SMALL_TYPE];
}

- (id)initWithKey:(NSString *)key type:(DownLoadFileType)type {
    if (self = [super init]) {
        _pathKey = key;
        _fileType = type;
        _taskCount = 0;
        _isAsync = NO;
        NSAssert(_pathKey != nil && _pathKey.length, @"path key is empty!!");
        
        NSString *dirPath = [NSString stringWithFormat:@"%@/%@", FileStorageDirectory, _pathKey];
        
        _docPath = [CS_FileManager dirPathInLibrary:dirPath];
        
        _context = [[DownloadContext alloc] initWithFile:[self indexFilePath]];
        _downloadArray = [[NSMutableArray alloc] init];
    }
    
    return self;
}

- (NSString *)directoryPath {
    return _docPath;
}

- (NSString *)localFilePath:(NSString *)url {
    return [NSString stringWithFormat:@"%@/%@", _docPath, [_context localFileNameWithUrl:url]];
}

- (NSString *)indexFilePath {
    return [NSString stringWithFormat:@"%@/index.plist", _docPath];
}

- (NSString *)fullPathOfLocalFile:(NSString *)file {
    if (!file) {
        return @"";
    }
    return [NSString stringWithFormat:@"%@/%@", _docPath, file];
}

- (NSArray *)fullPathOfLocalMiddleFile:(NSString *)file {
    if (!file) {
        return nil;
    }
    
    NSMutableArray *array = [[NSMutableArray alloc] init];
    [array addObject:[NSString stringWithFormat:@"%@/%@.dmmap", _docPath, file]];
    [array addObject:[NSString stringWithFormat:@"%@/%@.dmdata", _docPath, file]];
    
    return array;
}

- (NSInteger)getProgress {
    return [_context progress];
}

- (BOOL)isNotSyncing {
    if (!_context) {
        return YES;
    }
    
    return (_isAsync == NO);
}

- (NSData *)dataForUrl:(NSString *)url {
    if (!url) {
        return nil;
    }
    
    NSData *data = [[NSData alloc] initWithContentsOfFile:[self localFilePath:url]];
    
    return data;
}

- (void)asyncDownload:(NSArray *)urlArray {
    if (_isAsync) {
        return;
    }
    
    _isAsync = YES;
    
    [_context syncWithUrls:urlArray];
    [self _downLoadDatas];
}

- (void)_selectToDownloadWithNum:(NSInteger)num {
    NSDictionary *toLoadDict = _context.urlToAtoms;
    
    for (int32_t i = 0; i < num && _downloadArray.count; i++) {
        NSString *url = [_downloadArray objectAtIndex:0];
        [_downloadArray removeObjectAtIndex:0];
        DownloadContextAtom *atom = [toLoadDict objectForKey:url];
        NSString *localUrl = [self fullPathOfLocalFile:atom.localUrl];
        IKDownloadItem *downloadItem = [[IKDownloadItem alloc] init];
        
        downloadItem.url = url;
        downloadItem.priority = IKRequestPriorityLow;
        downloadItem.filePath = localUrl;
        
        IKDownloader *loader = [[IKDownloader alloc] initWithItem:downloadItem];
        
        atom.downloader = loader;
        [_context syncDownloadContextAtomWithUrl:url stat:MEFILE_TO_DOWNLOAD];
        //[loader load:self requestTag:'song'];
        loader.delegate = self;
        [loader start];
    }
}

- (void)_downLoadDatas {
    [_downloadArray removeAllObjects];
    NSDictionary *toLoadDict = _context.urlToAtoms;
    
    for (int i = 0; i < toLoadDict.allKeys.count; i++) {
        NSString *key = [toLoadDict.allKeys objectAtIndex:i];
        DownloadContextAtom *atom = [toLoadDict objectForKey:key];
        
        if (atom.stat == MEFILE_TO_DOWNLOAD) {
            if ([CS_FileManager isFileExists:[self fullPathOfLocalFile:atom.localUrl]]) {
                [_context syncDownloadContextAtomWithUrl:key stat:MEFILE_FINISH];
            } else {
                NSLog(@"%@ need to download %@", _pathKey, key);
                [_downloadArray addObject:key];
            }
        } else if (atom.stat == MEFILE_TO_DELETE) {
            if (atom.localUrl && atom.localUrl.length) {
                [CS_FileManager deleteFile:[self fullPathOfLocalFile:atom.localUrl]];
            }
            [_context delDownloadContextAtomWithUrl:key];
        } else if (atom.stat == MEFILE_FINISH) {
            //已经完成的不去下载
            if (![CS_FileManager isFileExists:[self fullPathOfLocalFile:atom.localUrl]]) {
                [_context syncDownloadContextAtomWithUrl:key stat:MEFILE_TO_DOWNLOAD];
                [_downloadArray addObject:key];
            }
        }
    }
    
    _taskCount = [_downloadArray count];
    
    if (_downloadArray.count == 0) {
        _isAsync = NO;
        return;
    }
    
    [self _selectToDownloadWithNum:1];
}


- (float)singleFileProgress:(NSString *)url {
    float prgvalue;
    NSDictionary *dict = _context.urlToAtoms;
    DownloadContextAtom *atom = [dict objectForKey:url];
    if (!atom) {
        return 0;
    }
    
    if (atom.stat == MEFILE_FINISH) {
        return 1.0;
    }
    
    if (atom.stat != MEFILE_TO_DOWNLOAD) {
        return 0;
    }
    
    IKDownloader *loader = (IKDownloader *)atom.downloader;
    
    if (!loader) {
        return 0;
    }
    
    // 下载进度的查询
    prgvalue = [loader progress];
    
    return prgvalue;
}

- (NSString *)localFilePathForUrl:(NSString *)url {
    if (!url) {
        return nil;
    }
    
    return [NSString stringWithFormat:@"%@/%@", _docPath, [_context localFileNameWithUrl:url]];
}

#pragma -mark  IKDownloader Delegate

- (void)Downloader:(IKDownloader *)downloader code:(NSInteger)code {
    IKDownloader *loader = downloader;
    NSString *url = loader ? loader.item.url : @"";
    
    if (!url) {
        return;
    }
    
    DownloadContextAtom *atom = [_context.urlToAtoms objectForKey:url];
    
    if (!atom) {
        code = -1;
    }
    
    if (0 == code) {
        if ([CS_FileManager isFileExists:[self fullPathOfLocalFile:atom.localUrl]]) {
            [_context syncDownloadContextAtomWithUrl:url stat:MEFILE_FINISH];
            if (RES_OK(@selector(didFinishWithSongUrl:))) {
                [_delegate didFinishWithSongUrl:url];
            }
        } else {
            code = -1;
        }
    }
    
    atom.downloader = nil;
    loader = nil;
    _taskCount--;
    
    if (_taskCount == 0) {
        _isAsync = NO;
        if (RES_OK(@selector(didFinishWithError:))) {
            [_delegate didFinishWithError:([_context isFinishedTaskCount] ? SMALL_STORAGE_STATUS_ALL : SMALL_STORAGE_STATUS_PART)];
        }
        [_context _syncFile];
    } else {
        [self _selectToDownloadWithNum:1];
    }
}

- (void)Downloader:(IKDownloader *)downloader progress:(int64_t)progress total:(int64_t)total {
    
}

@end

